#!/usr/bin/env python

import os
import sys
import string
import re
import StringIO
import copy
AVOF_name = [
"name",
"long_name",
"mime_type",
"extensions",
"priv_data_size",
"audio_codec",
"video_codec",
"write_header",
"write_packet",
"write_trailer",
"flags",
"set_parameters",
"interleave_packet",
"codec_tag",
"subtitle_codec",
"next",
]

AVOF_vaule = [
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"CODEC_ID_NONE,\n",
"CODEC_ID_NONE,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"CODEC_ID_NONE,\n",
"0,\n",
]

AVIF_name  = [
"name",
"long_name",
"priv_data_size",
"read_probe",
"read_header",
"read_packet",
"read_close",
"read_seek",
"read_timestamp",
"flags",
"extensions",
"value",
"read_play",
"read_pause",
"codec_tag",
"next",
]

AVIF_vaule =[
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
"0,\n",
]


AVCodecName =[
"name",
"type",
"id",
"priv_data_size",
"init",
"encode",
"close",
"decode",
"capabilities",
"next",
"flush",
"supported_framerates",
"pix_fmts",
"long_name",
"supported_samplerates",
"sample_fmts",
"channel_layouts",
]

AVCodecVaule = [
"0,",
"CODEC_TYPE_UNKNOWN,",
"CODEC_ID_NONE,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
"0,",
]
"AVOutputFormat","AVInputFormat","AVCodec"
iovname = {"AVOutputFormat":AVOF_name,
           "AVInputFormat":AVIF_name,
           "AVCodec":AVCodecName
           }

iovvalue = {"AVOutputFormat":AVOF_vaule,
           "AVInputFormat":AVIF_vaule,
           "AVCodec":AVCodecVaule
           }




class FFmpegException(Exception): pass

class FFmpegVC:
    def __init__(self, fpold, modpath, filename):
        self.fpold = fpold
        self.modpath = modpath
        self.fpnew = None
        self.txt = ""
        self.filename = filename
        self.codectagBock=""
        self.conditionFlag = 0
        self.conditionBlock =""
        self.avname = ""
        self.avtype = ""
        self.newblocks= [] # all blocks in one page
        self.newblock = "" # one block content
        self.newblockHeader = "" # if there is content about other like codec_tag
        self.newblcokName = "" # like "AVOutputFormat mymux = { \n"
        self.logfile = r"c:\ffmpeg.py.log.txt"
        self.log = open(self.logfile, "a")
        self.valueIdx = 0
        self.valueDefault = [] # the whole content between the top level '{' and '}', which define a mux/demux/en/decode
        self.IOCVariableName = [] # one of AVOF_name ,AVIF_name ,AVCodecName list

        self.matchIdx = 0

        self.lineHeader = "    "
        self.dummy = "                                                                          "#just dummy
        self.comment = "/* boirs@gmaildotcom .python */"


    re_dbblock = re.compile(r"(\b(AVInputFormat|AVOutputFormat|AVCodec)\b\s*([^=]*?)=\s*?{\s*(.*?)\s*?})\s*?;", re.DOTALL)
    av_type_lst = ["AVOutputFormat","AVInputFormat","AVCodec"]

    def run(self):
        self.txt = self.fpold.read()
        matchdb = self.re_dbblock.finditer(self.txt)
        if matchdb:
            self.fpnew = open(os.path.join(self.modpath, self.filename), "w")
            for db in matchdb:
                newdb = self.buildNewDB(db)
                self.newblocks.append(newdb)
            self.dbsub()
            self.fpnew.close()
        self.fpold.close()
        self.log.close()

    regex_remove_comment = re.compile(r"/\*.*?\*/|//.*?$", re.MULTILINE|re.DOTALL)

    def buildNewDB(self, olddb):
        wholedb = olddb.group(1) # the whole block
        self.avtype = olddb.group(2) # O or I?
        self.avname = olddb.group(3) # like my_mux
        self.newblcokName = self.avtype + " " +self.avname + "= {\n"
        dbdata = olddb.group(4)

        dbdata = self.regex_remove_comment.sub("", dbdata)
        strFile = StringIO.StringIO(dbdata)

        self.valueDefault = copy.copy(iovvalue[self.avtype])
        self.IOCVariableName = iovname[self.avtype]
        #print self.IOCVariableName.index("name")

        self.valueIdx = 0

        for line in strFile:
            afterCheckEmpty = line.strip()
            if not afterCheckEmpty:
                continue
            if afterCheckEmpty[0] != '#':#debug
                bool0 = afterCheckEmpty.count("[") == afterCheckEmpty.count("]")
                bool1 = afterCheckEmpty.count("(") == afterCheckEmpty.count(")")
                bool2 = afterCheckEmpty.count("{") == afterCheckEmpty.count("}")
                bool3 = afterCheckEmpty.count('"')%2 == 0
                bool4 = afterCheckEmpty.rfind(',') == len(afterCheckEmpty) - 1
                boolall = [bool0, bool1, bool2, bool3, bool4]
                if not all(boolall):
                    self.log.write(self.filename)
                    self.log.write(self.avname)
                    self.log.write(dbdata)
                    print self.filename + " has an error"
                    indexxxx = 0
                    for item in boolall:
                        if not item:
                            print indexxxx
                        else:
                            indexxxx += 1
                    raise FFmpegException, " error "


            #process line by line
            avalue = ""
            if str(afterCheckEmpty[0:3]) == '#if':
                self.conditionFlag = 1

            if self.conditionFlag == 1:
                if str(afterCheckEmpty[0:3]) == '#if':   #if
                    self.conditionBlock = ""
                    self.conditionBlock += afterCheckEmpty + "\n"
                elif str(afterCheckEmpty[0:3]) == '#el': # #elif |#else
                    self.conditionBlock += afterCheckEmpty + "\n"
                elif str(afterCheckEmpty[0:4]) == '#end': ##end
                    self.conditionBlock += afterCheckEmpty + "\n"
                    self.conditionFlag = 0
                    self.valueDefault[self.valueIdx] = self.conditionBlock
                    self.valueIdx += 1
                else:
                    avalue = self.processLine(afterCheckEmpty)
                    self.conditionBlock += avalue
            else:
                avalue = self.processLine(afterCheckEmpty)
                self.valueDefault[self.valueIdx] = avalue
                self.valueIdx += 1
        tempValueDefault = ""
        vr = range(self.valueIdx)
        for item in vr:
            tempValueDefault += self.valueDefault[item]

        the_whole_new_block = self.newblockHeader + self.newblcokName + tempValueDefault + "};\n"
        #print the_whole_new_block
        return the_whole_new_block


    def processLine(self, aline):
        if aline[0] == '.':
            return self.processDotLine(aline)
        else:
            return self.processNormalLIne(aline)

    #dotRe = re.compile(r"\.(.+?)\s*=\(.+?\)({.+?})\s*,")
    dotRe = re.compile(r"\.(.+?)\s*=\s*(.*?)\s*,")
    dotCodecTagRe = re.compile(r".codec_tag\s*=\s*\(.*?\)\s*({.*})\s*,")
    def processDotLine(self, aline):
        dot_mo = self.dotRe.match(aline)
        nameOfdot = dot_mo.group(1)
        valueOfDot = dot_mo.group(2)
        self.valueIdx = self.IOCVariableName.index(nameOfdot)
        if nameOfdot == "codec_tag":
            dot_moct = self.dotCodecTagRe.match(aline)
            valueOfDot = dot_moct.group(1)
            valueOfDot = self.processCodecTag(valueOfDot)
        return valueOfDot+ ",\n"

    def processNormalLIne(self, aline):
        normalValue = aline.strip(',')
        findcodectag = 0
        try:
            findcodectag = self.valueIdx == self.IOCVariableName.index("codec_tag")
        except:
            print "codec_tag execept"

        if findcodectag == 1:
            normalValue = self.processCodecTag(normalValue)
        return normalValue + ",\n"

    def processCodecTag(self, valueofDot):
        ctname = "ct_"+self.avname
        self.newblockHeader = "static const struct AVCodecTag * const ct_{0} [] = {1};".format(ctname, valueofDot) + "\n"
        return ctname

    def dbsub(self):
        newtxt = self.re_dbblock.sub(self.repfuction, self.txt)
        #print newtxt
        self.fpnew.write(newtxt)

    def repfuction(self, mo):
        substr = self.newblocks[self.matchIdx]
        self.matchIdx += 1
        return substr

def test():
    fpold = open(r"J:\svkwork\ffmpeg2\libavformat\asf-enc.c")
    fpnew = open(r"J:\svkwork\ffmpeg2\libavformat\new\asf-enc.c", "w")
    fs = FFmpegVC(fpold, fpnew, "asf-enc.c").run()
    print "finished"

def main():
    ori_fm = r"J:\svkwork\ffmpeg\ffmpeg_ori\libavformat"
    mod_fm = r"J:\svkwork\ffmpeg\ffmpeg_mod\libavformat"
    ori_codec = r"J:\svkwork\ffmpeg\ffmpeg_ori\libavcodec"
    mod_codec = r"J:\svkwork\ffmpeg\ffmpeg_mod\libavcodec"

    filecoll = os.listdir(ori_fm)
    for fl in filecoll:
        fullfilename = os.path.join(ori_fm, fl)
        if os.path.isfile(fullfilename) and os.path.splitext(fl)[1] == ".c" :
            fpold = open(fullfilename)
            fs = FFmpegVC(fpold, mod_fm, fl).run()

    filecoll = os.listdir(ori_codec)
    for fl in filecoll:
        fullfilename = os.path.join(ori_codec, fl)
        if os.path.isfile(fullfilename) and os.path.splitext(fl)[1] == ".c" :
            fpold = open(fullfilename)
            try:
                fs = FFmpegVC(fpold, mod_fm, fl).run()
            except:
                print "errro"

    print "finish"



if __name__ == "__main__":
    main()
